package main

import (
	"log"
	"net"
)

type UdpServerHandler interface {
	OnRecv(conn *net.UDPConn, remoteAddr *net.UDPAddr, msg []byte)
}

type UdpServer struct {
	conn    *net.UDPConn
	quit    chan interface{}
	handler UdpServerHandler
}

func NewUdpServer(addr string, handler UdpServerHandler) *UdpServer {
	s := &UdpServer{
		conn:    nil,
		quit:    make(chan interface{}),
		handler: handler,
	}

	udpAddr, err := net.ResolveUDPAddr("udp", addr)
	if err != nil {
		log.Fatal(err)
	}

	conn, err := net.ListenUDP("udp", udpAddr)
	if err != nil {
		log.Fatal(err)
	}

	s.conn = conn
	go s.serve()
	return s
}

func (s *UdpServer) Stop() {
	close(s.quit)
	s.conn.Close()
}

func (s *UdpServer) Addr() string {
	return s.conn.LocalAddr().String()
}

func (s *UdpServer) Network() string {
	return s.conn.LocalAddr().Network()
}

func (s *UdpServer) serve() {
	for {
		buf := make([]byte, 2048)

		n, remoteAddr, err := s.conn.ReadFromUDP(buf)
		if err != nil {
			select {
			case <-s.quit:
				log.Printf("Closing server %s %s", s.Network(), s.Addr())
				return
			default:
				log.Println(err)
			}
		} else if nil == s.handler {
			log.Printf("Recv data from %s %s, but handler is nil, ignored", s.Network(), s.Addr())
		} else {
			go s.handler.OnRecv(s.conn, remoteAddr, buf[:n])
		}
	}
}
